home *** CD-ROM | disk | FTP | other *** search
- // MSAETextUtils.c
- //
- // Original version by Jon Lansdell and Nigel Humphreys.
- // 4.0 and 3.1 updates by Greg Sutton.
- // ©Apple Computer Inc 1996, all rights reserved.
-
- /*
- 14-Nov-95 : GS : Removed reliance on compiler setting local variable to zero
- in GetInsertDescFromInsertHere().
- */
-
- #include "MSAETextUtils.h"
-
- #include "MSAEUtils.h"
- #include "MSWindow.h" // for DPtrFromWindowPtr()
- #include "MSAERecording.h"
-
-
- #include <AEPackObject.h>
-
-
-
- // ----------------------------------------------------------------------------------
- // Name: PutStyledTextFromDescIntoTEHandle
- // Purpose: Takes the text in an AEDesc containing typeIntlText and puts it in
- // a styled text edit record at the current insertion point.
- // Looks for typeIntlText, typeStyledText, typeChar in that order.
- // ----------------------------------------------------------------------------------
-
- OSErr PutStyledTextFromDescIntoTEHandle(const AEDesc *sourceTextDesc, TEHandle theHTE)
- {
- AEDesc styledTextDesc = { typeNull, NULL };
- AEDesc textStyleDesc = { typeNull, NULL };
- AEDesc rawTextDesc = { typeNull, NULL };
- OSErr myErr;
-
- // Coerce to an AERecord and then extract the parts of the
- // styled text - works for typeIntlText, typeStyledText
-
- myErr = AECoerceDesc(sourceTextDesc, typeAERecord, &styledTextDesc);
-
- if (noErr == myErr)
- {
- myErr = AEGetKeyDesc(&styledTextDesc, keyAEText,
- typeChar, &rawTextDesc);
-
- myErr = AEGetKeyDesc(&styledTextDesc, keyAEStyles,
- typeScrapStyles, &textStyleDesc);
- }
- else
- {
- myErr = AECoerceDesc(sourceTextDesc, typeChar, &rawTextDesc);
-
- textStyleDesc.dataHandle = NULL; // so that TEStylInsert acts like TEInsert
- }
-
- HLock((Handle)rawTextDesc.dataHandle);
-
- TEDelete(theHTE); // Insert over current selection
- TEStylInsert((const void *) (*rawTextDesc.dataHandle),
- GetHandleSize(rawTextDesc.dataHandle),
- (StScrpHandle) textStyleDesc.dataHandle,
- theHTE);
-
- HUnlock((Handle)rawTextDesc.dataHandle);
-
- (void)AEDisposeDesc(&textStyleDesc);
- (void)AEDisposeDesc(&rawTextDesc);
- (void)AEDisposeDesc(&styledTextDesc);
-
- return(myErr);
- }
-
-
- TEHandle TEHandleFromWindow(WindowPtr theWindow)
- {
- DPtr docPtr;
- TEHandle result = NULL;
-
- if (! theWindow)
- return(NULL);
-
- docPtr = DPtrFromWindowPtr(theWindow);
-
- if (docPtr)
- result = docPtr->theText;
-
- return(result);
- }
-
- TEHandle TEHandleFromTextToken(TextToken* aToken)
- {
- if (! aToken)
- return(NULL);
-
- return(TEHandleFromWindow(aToken->tokenWindow));
- }
-
-
- OSErr GetInsertDescFromInsertHere(AEDesc* insertHereDesc, AEDesc* insertDesc, DescType* insertType)
- {
- AEDesc insertRec = {typeNull, NULL},
- objectSpec = {typeNull, NULL};
- DescType returnedType;
- Size actualSize;
- OSErr err = noErr;
-
- switch (insertHereDesc->descriptorType)
- {
- case typeInsertionLoc:
- err = AECoerceDesc(insertHereDesc, typeAERecord, &insertRec);
- if (noErr != err) goto done;
-
- err = AEGetKeyPtr(&insertRec, keyAEPosition, typeEnumeration, &returnedType,
- (Ptr)insertType, sizeof(insertType), &actualSize);
- if (noErr != err) goto done;
-
- err = AEGetKeyDesc(&insertRec, keyAEObject, typeWildCard, &objectSpec);
- if (objectSpec.descriptorType != typeNull)
- {
- err = AEResolve(&objectSpec, kAEIDoMinimum, insertDesc);
- if (err != noErr) goto done;
- }
- break;
-
- case typeObjectSpecifier:
- err = AEResolve(insertHereDesc, kAEIDoMinimum, insertDesc);
- if (noErr != err) goto done;
- *insertType = insertDesc->descriptorType;
- break;
-
- case typeNull: // No insertion location given
- *insertType = typeNull;
- break;
-
- case typeType:
- *insertType = *(DescType *)*insertHereDesc->dataHandle;
- break;
-
- default: // Just copy the descriptor
- err = AEDuplicateDesc(insertHereDesc, insertDesc);
- if (noErr != err) goto done;
- *insertType = insertDesc->descriptorType;
- }
-
- done:
- if (insertRec.dataHandle)
- AEDisposeDesc(&insertRec);
- if (objectSpec.dataHandle)
- AEDisposeDesc(&objectSpec);
-
- return(err);
- }
-
- // This routine returns an enumerated type describing the relative position
- // of one TextToken to another.
-
- TokenWithinType TokenWithinToken(TextToken* container, TextToken* token, short* numPartial)
- {
- TokenWithinType result;
-
- if (token->tokenOffset + token->tokenLength < container->tokenOffset)
- result = kTokenBefore;
- else if (container->tokenOffset + container->tokenLength < token->tokenOffset)
- result = kTokenAfter;
- else if (token->tokenOffset >= container->tokenOffset
- && token->tokenOffset + token->tokenLength <= container->tokenOffset + container->tokenLength)
- result = kTokenWithin;
- else if (token->tokenOffset < container->tokenOffset)
- {
- result = kTokenPartialBefore;
- if (numPartial)
- *numPartial = token->tokenOffset + token->tokenLength - container->tokenOffset;
- }
- else
- {
- result = kTokenPartialAfter;
- if (numPartial)
- *numPartial = container->tokenOffset + container->tokenLength - token->tokenOffset;
- }
-
- return(result);
- }
-
-
- OSErr TextTokenFromDocumentToken(WindowToken* theWindowToken, TextToken* theTextToken)
- {
- DPtr docPtr;
-
- docPtr = DPtrFromWindowPtr(theWindowToken->tokenWindow);
-
- if (! docPtr)
- return(errAENoSuchObject);
- // Create our text token
- theTextToken->tokenWindow = theWindowToken->tokenWindow;
- theTextToken->tokenOffset = 1; // Start at 1
- theTextToken->tokenLength = (**docPtr->theText).teLength; // through whole length
-
- return(noErr);
- }
-
-
- OSErr TextTokenFromDocumentDesc(AEDesc* windowDesc, TextToken* theToken)
- {
- AEDesc aDesc = {typeNull, NULL};
- WindowToken aWindowToken;
- Size actualSize;
- OSErr err;
-
- err = AECoerceDesc(windowDesc, typeMyDocument, &aDesc);
- if (noErr != err) goto done;
-
- GetRawDataFromDescriptor(&aDesc, (Ptr)&aWindowToken,
- sizeof(aWindowToken), &actualSize);
-
- err = TextTokenFromDocumentToken(&aWindowToken, theToken);
-
- done:
- (void)AEDisposeDesc(&aDesc);
-
- return(err);
- }
-
-
- OSErr TextDescFromDocumentToken(WindowToken* theWindowToken, AEDesc* textDesc)
- {
- TextToken aToken;
- OSErr err;
-
- err = TextTokenFromDocumentToken(theWindowToken, &aToken);
- if (noErr != err) goto done;
-
- err = AECreateDesc(typeMyText, (Ptr)&aToken, sizeof(aToken), textDesc);
-
- done:
- return(err);
- }
-
-
- OSErr TextDescFromDocumentDesc(AEDesc* windowDesc, AEDesc* textDesc)
- {
- TextToken aToken;
- OSErr err;
-
- err = TextTokenFromDocumentDesc(windowDesc, &aToken);
- if (noErr != err) goto done;
-
- err = AECreateDesc(typeMyText, (Ptr)&aToken, sizeof(aToken), textDesc);
-
- done:
- return(err);
- }
-
-
- void MoveToNonSpace(short *start, short limit, charsHandle myChars)
- // Treats space, comma, full stop, ; and : as space chars
- {
- short x;
-
- while (*start <= limit) {
- x = (**myChars)[*start];
- if (IsWhiteSpace(x))
- (*start) +=1;
- else
- return;
- }
- }
-
- void MoveToSpace(short *start, short limit, charsHandle myChars)
- // Treats space,comma, full stop, ; and : as space chars
- {
- short x;
-
- while (*start <= limit)
- {
- x = (**myChars)[*start];
- if (! IsWhiteSpace(x))
- (*start)++;
- else
- return;
- }
- }
-
- void MoveToEndOfParagraph(short *start, short limit, charsHandle myChars)
- // Treats CR as end of paragraph
- {
- short x;
-
- while (*start <= limit)
- {
- x = (**myChars)[*start];
- if (! IsParagraphDelimiter(x)) // had x != CR
- (*start)++;
- else
- return;
- }
- }
-
-
- // This routine counts the given elementType between startAt and
-
- OSErr CountTextElements(TEHandle inTextHandle, short startAt,
- short forHowManyChars, DescType elementType, short* result)
- {
- charsHandle theChars;
- short limit,
- start;
- OSErr err = noErr;
-
- switch (elementType)
- {
- case cInsertionPoint: // Always one more insertion location than characters
- *result = forHowManyChars + 1;
- break;
-
- case cChar: // Easy
- *result = forHowManyChars;
- break;
-
- case cText:
- *result = 1;
- break;
-
- case cWord: // Cycle through - counting
- case cParagraph:
- theChars = (charsHandle)(**inTextHandle).hText;
- start = startAt - 1; // Convert to zero based
- limit = start + forHowManyChars - 1; // when passed one based
- *result = 0;
- MoveToNonSpace(&start, limit, theChars);
- while (start <= limit)
- {
- (*result)++;
- switch (elementType)
- {
- case cWord:
- MoveToSpace(&start, limit, theChars);
- break;
-
- case cParagraph:
- MoveToEndOfParagraph(&start, limit, theChars);
- break;
- }
- MoveToNonSpace(&start, limit, theChars);
- }
- break;
-
- default:
- *result = -1;
- err = errAEBadKeyForm;
- }
-
- return(err);
- } // CountTextElements
-
- OSErr GetDescOfNthTextElement(short index, DescType elementType,
- TextToken* containerToken, AEDesc* result)
- {
- DPtr docPtr;
- TextToken theToken;
- short start,
- maxChars,
- elementCount,
- limit,
- elementStart;
- charsHandle theChars;
- OSErr err;
-
- if (! containerToken)
- return(errAEEmptyListContainer);
-
- docPtr = DPtrFromWindowPtr(containerToken->tokenWindow);
- start = containerToken->tokenOffset - 1; // Zero based
- maxChars = containerToken->tokenLength;
-
- err = CountTextElements(docPtr->theText, containerToken->tokenOffset,
- maxChars, elementType, &elementCount);
- if (noErr != err) return(err);
-
- if (index < 0) // Change a negative index to positive
- index = elementCount + index + 1;
-
- if (index > elementCount) // Got given an index out of range
- return(errAEIllegalIndex);
-
- // Set the window that the token relates to
- theToken.tokenWindow = containerToken->tokenWindow;
-
- switch (elementType)
- {
- case cInsertionPoint:
- theToken.tokenOffset = start + index - 1;
- theToken.tokenLength = 0;
- break;
-
- case cChar: // Easy - just the start point + the index
- theToken.tokenOffset = start + index;
- theToken.tokenLength = 1;
- break;
-
- case cText:
- theToken.tokenOffset = start + index;
- theToken.tokenLength = maxChars;
- break;
-
- case cWord:
- case cParagraph:
- theChars = (charsHandle)(**(docPtr->theText)).hText;
- limit = start + maxChars - 1;
- MoveToNonSpace(&start, limit, theChars);
- while ((start <= limit) && (index > 0))
- {
- index--;
- elementStart = start;
- switch (elementType)
- {
- case cWord:
- MoveToSpace(&start, limit, theChars);
- break;
-
- case cParagraph:
- MoveToEndOfParagraph(&start, limit, theChars);
- break;
- }
- theToken.tokenLength = start - elementStart;
- MoveToNonSpace(&start, limit, theChars);
- }
- theToken.tokenOffset = elementStart + 1; // Convert to one based
- break;
- }
-
- err = AECreateDesc(typeMyText, (Ptr)&theToken, sizeof(theToken), result);
-
- return(err);
- }
-
-
- char GetTEHChar(TEHandle aTEH, short offset)
- {
- char result;
-
- offset--; // This is now 0 based
-
- if (offset < 0 || offset >= (*aTEH)->teLength)
- return('\0');
-
- result = *(char *)((*(**aTEH).hText) + offset);
-
- return(result);
- }
-
- Boolean IsAtStart(TextToken* theToken)
- {
- Boolean result;
- // Is at start if offset is at 1
- result = (theToken->tokenOffset == 1);
-
- return(result);
- }
-
- Boolean IsAtEnd(TextToken* theToken)
- {
- TEHandle aTEH;
- Boolean result;
-
- aTEH = TEHandleFromTextToken(theToken);
- // Does it go to the end?
- result = (theToken->tokenOffset + theToken->tokenLength >= (**aTEH).teLength);
-
- return(result);
- }
-
- Boolean IsWhiteSpace(short aChar)
- {
- Boolean result;
-
- result = (aChar == ' ' || aChar == ',' || aChar == '.'
- || aChar == ':' || aChar == LF || aChar == CR);
-
- return(result);
- }
-
- Boolean IsParagraphDelimiter(short aChar)
- {
- Boolean result;
-
- result = (aChar == CR);
-
- return(result);
- }
-
- Boolean IsContentsToken(TextToken* theToken)
- {
- return(IsAtStart(theToken) && IsAtEnd(theToken));
- }
-
- Boolean IsParagraphToken(TextToken* theToken, short* start, short* end)
- {
- TEHandle aTEH;
- OSErr err;
- short number;
- Boolean fStart,
- fEnd,
- result;
-
- aTEH = TEHandleFromTextToken(theToken);
-
- fStart = IsAtStart(theToken) || IsParagraphDelimiter(GetTEHChar(aTEH, theToken->tokenOffset - 1));
- fEnd = IsAtEnd(theToken) || IsParagraphDelimiter(GetTEHChar(aTEH, theToken->tokenOffset + theToken->tokenLength));
-
- if (fStart && fEnd)
- {
- // need to do a count of the paragraphs
-
- err = CountTextElements(aTEH, theToken->tokenOffset,
- theToken->tokenLength, cParagraph, &number);
-
- // count text elements before it i.e. offset == 0 limit == theToken->tokenOffset
-
- if (IsAtStart(theToken))
- *start = 1;
- else
- { // From beginning to charracter before start of paragraph
- err = CountTextElements(aTEH, 1,theToken->tokenOffset - 1, cParagraph, start);
- (*start)++;
- }
-
- *end = *start + number - 1;
-
- result = true;
- }
- else
- result = false;
-
- return(result);
- }
-
- Boolean IsWordToken(TextToken* theToken, short* start, short* end)
- {
- TEHandle aTEH;
- OSErr err;
- short number;
- Boolean fStart,
- fEnd,
- result;
-
- aTEH = TEHandleFromTextToken(theToken);
-
- fStart = IsAtStart(theToken) || IsWhiteSpace(GetTEHChar(aTEH, theToken->tokenOffset - 1));
- fEnd = IsAtEnd(theToken) || IsWhiteSpace(GetTEHChar(aTEH, theToken->tokenOffset + theToken->tokenLength));
-
- if (fStart && fEnd)
- {
- // need to do a count of the words
-
- err = CountTextElements(aTEH, theToken->tokenOffset,
- theToken->tokenLength, cWord, &number);
-
- // count text elements before it i.e. offset == 0 limit == theToken->tokenOffset
-
- if (IsAtStart(theToken))
- *start = 1;
- else
- { // From beginning to charracter before start of word
- err = CountTextElements(aTEH, 1, theToken->tokenOffset - 1, cWord, start);
- (*start)++;
- }
-
- *end = *start + number - 1;
-
- result = true;
- }
- else
- result = false;
-
- return(result);
- }
-
-
- DescType GetTextTokenType(TextToken* theToken, short* start, short* end)
- {
- DescType result;
-
- *start = *end = -1; // Just set to the same value
-
- if (! theToken->tokenLength)
- {
- result = cInsertionPoint;
- }
- else if (IsContentsToken(theToken))
- {
- result = pContents;
- }
- else if (IsParagraphToken(theToken, start, end))
- {
- result = cParagraph;
- }
- else if (IsWordToken(theToken, start, end))
- {
- result = cWord;
- }
- else
- {
- result = cChar;
- *start = theToken->tokenOffset;
- *end = theToken->tokenOffset + theToken->tokenLength - 1;
- }
-
- return(result);
- }
-
- OSErr MakeContentsSpecifier(TextToken* theToken, AEDesc* result)
- {
- AEDesc docSpec = {typeNull, NULL},
- contentsDesc = {typeNull, NULL};
- DescType propertyID;
- OSErr err;
-
- err = MakeDocumentObj(theToken->tokenWindow, &docSpec);
- if (noErr != err) goto done;
-
- propertyID = pContents;
- err = AECreateDesc(typeType, (Ptr)&propertyID, sizeof(DescType), &contentsDesc);
- if (err != noErr) goto done;
- err = CreateObjSpecifier(cProperty, &docSpec, formPropertyID, &contentsDesc, false, result);
-
- done:
- (void)AEDisposeDesc(&docSpec);
- (void)AEDisposeDesc(&contentsDesc);
-
- return(err);
- }
-
-
- OSErr MakeAbsoluteTextSpecifier(WindowPtr theWindow, DescType textType, long index, AEDesc* result)
- {
- AEDesc docSpec = {typeNull, NULL},
- absoluteDesc = {typeNull, NULL};
- OSErr err;
-
- if (theWindow)
- {
- err = MakeDocumentObj(theWindow, &docSpec);
- if (noErr != err) goto done;
- }
- // else just use the NULL'ed value
-
- err = AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(index), &absoluteDesc);
- if (err != noErr) goto done;
- err = CreateObjSpecifier(textType, &docSpec, formAbsolutePosition,
- &absoluteDesc, false, result);
-
- done:
- (void)AEDisposeDesc(&docSpec);
- (void)AEDisposeDesc(&absoluteDesc);
-
- return(err);
- }
-
-
- OSErr MakeInsertionPointSpecifier(TextToken* theToken, AEDesc* result)
- {
- AEDesc relativeToSpec = {typeNull, NULL},
- relativeDesc = {typeNull, NULL};
- DescType relativeType;
- OSErr err;
-
- if (IsAtStart(theToken)) // Before contents (whether there are any or not)
- {
- relativeType = kAEPrevious;
- err = MakeContentsSpecifier(theToken, &relativeToSpec);
- }
- else if (IsAtEnd(theToken)) // After last character
- {
- relativeType = kAENext;
- //err = MakeContentsSpecifier(theToken, &relativeToSpec);
- err = MakeAbsoluteTextSpecifier(theToken->tokenWindow, cChar, -1, &relativeToSpec);
- }
- else // Has a character it can go before
- {
- relativeType = kAEPrevious;
- err = MakeAbsoluteTextSpecifier(theToken->tokenWindow, cChar, theToken->tokenOffset, &relativeToSpec);
- }
-
- if (noErr != err) goto done;
-
- err = AECreateDesc(typeEnumerated, &relativeType, sizeof(relativeType), &relativeDesc);
- if (noErr != err) goto done;
- err = CreateObjSpecifier(cInsertionPoint, &relativeToSpec, formRelativePosition,
- &relativeDesc, false, result);
-
- done:
- (void)AEDisposeDesc(&relativeToSpec);
- (void)AEDisposeDesc(&relativeDesc);
-
- return(err);
- }
-
- OSErr GetIndexSpecifier(TextToken* theToken, DescType textType, long index, AEDesc* result)
- {
- OSErr err;
-
- switch (textType)
- {
- case cInsertionPoint:
- err = MakeInsertionPointSpecifier(theToken, result);
- break;
-
- case pContents:
- err = MakeContentsSpecifier(theToken, result);
- break;
-
- case cParagraph:
- case cWord:
- case cChar:
- err = MakeAbsoluteTextSpecifier(theToken->tokenWindow, textType, index, result);
- break;
-
- default:
- err = errAETypeError;
- }
-
- return(err);
- }
-
-
- OSErr GetTextTokenObjectSpecifier(TextToken* theToken, AEDesc* result)
- {
- AEDesc docSpec = {typeNull, NULL},
- startSpec = {typeNull, NULL},
- endSpec = {typeNull, NULL},
- rangeDesc = {typeNull, NULL};
- DescType textType;
- short start,
- end;
- OSErr err;
-
- textType = GetTextTokenType(theToken, &start, &end);
-
- err = GetIndexSpecifier(theToken, textType, start, &startSpec);
- if (noErr != err) goto done;
-
- if (start != end) // Sort out rest of range specifier
- {
- err = GetIndexSpecifier(theToken, textType, end, &endSpec);
- if (noErr != err) goto done;
-
- err = CreateRangeDescriptor(&startSpec, &endSpec, false, &rangeDesc);
- if (noErr != err) goto done;
-
- err = MakeDocumentObj(theToken->tokenWindow, &docSpec);
- if (noErr != err) goto done;
-
- err = CreateObjSpecifier(cText, &docSpec, formRange, &rangeDesc, false, result);
- }
- else
- err = AEDuplicateDesc(&startSpec, result);
-
- done:
- (void)AEDisposeDesc(&docSpec);
- (void)AEDisposeDesc(&startSpec);
- (void)AEDisposeDesc(&endSpec);
- (void)AEDisposeDesc(&rangeDesc);
-
- return(err);
- }
-